<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>在线客服</title>
  <link rel="stylesheet" href="/static/admin/css/chat.css">
</head>

<body>
  <div id="app" v-cloak>
    <div class="chat-box">
      <div class="contact-box">
        <el-input v-model="search" placeholder="搜索">
          <i class="el-icon-search el-input__icon" slot="suffix" @click="onSearch">
          </i>
        </el-input>
        <ul class="contact-list">
          <li class="contact-item" :class="{avtive:userActive.user_id==item.user_id}"
            v-for="(item,index) in contactList" :key="index" @click="onCantact(item.user_id)">
            <el-badge :value="item.msg_num" class="badge-box" :max="99" :hidden="item.msg_num<=0">
              <img :src="`${item.avatar}`" alt="" class="avatar">
            </el-badge>
            <div class="content-box">
              <div class="info-box">
                <h2 class="username">{{item.nick_name}}</h2>
                <div class="time-box">{{item.update_time*1000 | timeCalendar }}</div>
              </div>
              <p class="hot-news">{{item.msg}}</p>
            </div>
          </li>
        </ul>
      </div>
      <div class="chat-room-box">
        <div class="chat-top-box">
          <div class="user-box">
            <!-- <img :src="userActive.avatar" alt="" class="avatar"> -->
            <h2>{{userActive?.nick_name}}</h2>
          </div>
        </div>
        <ul class="msg-box">
          <li class="msg-item" :class="{my:item.type==2}" v-for="(item,index) in msgList" :key="index">
            <img :src="`${item.type==2?'/static/admin/images/cs.png':userActive?.avatar}`" alt="" class="avatar">
            <div class="msg-info">
              <!-- <h5 class="username">刘德华</h5> -->
              <p class="msg-content">{{item.msg}}</p>
            </div>
          </li>
        </ul>
        <div class="send-msg">
          <el-input class="text" type="textarea" v-model="msg" placeholder="发送内容" :rows="2" resize="none"
            @keyup.native.ctrl.enter="send">
          </el-input>
          <div>
            <span class="send-tisp">Ctrl+Enter 发送</span>
            <el-button type="primary" size="small" @click="send">发送</el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.1/axios.min.js"></script>
<script src="https://unpkg.com/moment@2.29.4/min/moment.min.js"></script>
<script src="https://unpkg.com/moment@2.29.4/locale/zh-cn.js"></script>
<script>

  new Vue({
    el: '#app',
    data() {
      return {
        // obj: JSON.parse(this.$route.query._chat),
        socketUrl: "wss://bfyc.jiazhengdashi.com/wss",
        obj: {},
        actions: [{ name: "123456" }],
        msgList: [],
        msg: "",
        showActionSheet: false,
        websock: "",
        chatToken: "",
        isLoadHistory: false,
        finished: false,
        token: "",
        isSend: false,
        socket: null,
        pageIndex: 1,
        lockReconnect: false,
        isOnline: false,
        networkStatus: true,
        search: '',
        contactList: [],
        userActive: null,
        socketToken: '',
        networkStatusFull: null,
        windowFocus: false,
        focusInterval: null
      };
    },
    created() {
      this.chatroomtokenlist()
    },
    mounted() {
      window.onblur = () => {
        this.windowFocus = false
      }
      window.onfocus = () => {
        this.windowFocus = true
        this.contactList.forEach(item => {
          if (item.cm_id == this.userActive.cm_id && this.windowFocus) {
            item.msg_num = 0
          }
        });
      }
      window.addEventListener("online", this.monitorNetworkStatus);
      window.addEventListener("offline", this.monitorNetworkStatus);
    },
    destroyed() {
      if (this.socket) this.socket.close();
      this.focusInterval && clearInterval(this.focusInterval)
      window.removeEventListener("online", this.monitorNetworkStatus);
      window.removeEventListener("offline", this.monitorNetworkStatus);
    },
    filters: {
      timeCalendar(time) {
        return moment(time).calendar(null, {
          sameDay: 'HH:mm',
          nextDay: '[明天]',
          nextWeek: 'dddd',
          lastDay: '[昨天]',
          lastWeek: 'ddd',
          sameElse: 'MM月DD日',
        })

      }
    },
    methods: {
      // 获取聊天室专属token
      getChatToken(string) {
        axios
          .get('/chatroom/chatroomtoken', {
            params: {
              user_id: this.userActive.user_id,
              string: this.socketToken,
            },
          })
          .then((res) => {
            if (res.data.code == 1) {
              this.token = res.data.data.token;
            } else if (res.data.code == -1) {
              Dialog.alert({
                message: res.data.msg,
              }).then(() => {
                // on close
                this.$router.go(-1);
              });
            }
          });
      },
      // 监听网络状态
      monitorNetworkStatus(e) {
        this.lockReconnect = e.type == "offline";
        if (!this.lockReconnect) {
          this.networkStatusFull.close()
          this.createWebSocket();
        } else {
          this.networkStatusFull = this.$loading({
            lock: true,
            text: '网络不可用',
            spinner: 'el-icon-close',
            customClass: 'my-loading'
          });
        }
      },
      // 建立连接
      initWebSocket() {
        this.socket.onopen = () => {
          console.log("连接成功");
        };
        this.socket.onmessage = (res) => {
          const data = JSON.parse(res.data);
          if (data.code == 1 || data.code == 2) {
            const newMsg = data.code == 1 ? this.msg : data.msg
            const type = data.code == 1 ? 2 : 1
            this.msgList.push({ type, msg: newMsg });
            this.contactList.forEach(item => {
              if (item.cm_id == this.userActive.cm_id) {
                item.msg = newMsg
                item.update_time = data.time
                if (!this.windowFocus) item.msg_num += 1
              }
            });
            this.isSend = false;
            this.msg = "";
            this.autoScrollButtom();
          } else if (data.code == -1) {
            this.$message.error("发送失败");
          } else {
            this.socketToken = data.string
            this.getChatToken();
          }
        };
        this.socket.onclose = (e) => {
          if (e.code != 1000) this.reconnect();
          console.log("连接关闭", e.code, e.reason, e.wasClean);
        };
        this.socket.onerror = () => {
          this.reconnect();
          console.log("连接失败");
        };
      },
      // 连接 ws
      createWebSocket() {
        try {
          if ("WebSocket" in window) {
            this.socket = new WebSocket(this.socketUrl);
          } else {
            Notify({
              type: "danger",
              message: "您的浏览器不支持websocket协议",
              duration: 0,
            });
          }
          this.initWebSocket();
        } catch (e) {
          this.reconnect();
          console.error(e);
        }
      },
      // 断开自动连接
      reconnect() {
        if (this.lockReconnect) return;
        this.lockReconnect = true;
        //没连接上会一直重连，设置延迟避免请求过多
        setTimeout(() => {
          this.createWebSocket();
          this.lockReconnect = false;
        }, 2000);
      },
      // 获取聊天室历史消息
      getMessageList(cb) {
        axios.get('/chatroom/gethistoricaldata', {
          params: {
            page: this.pageIndex,
            limit: 10,
            cm_id: this.userActive.cm_id,
          },
        }).then((res) => {
          if (res.data.code == 1) {
            let list = res.data.data.data.reverse();
            this.msgList.unshift(...list);
            if (list.length < 10) {
              this.finished = true;
            }
            if (this.pageIndex == 1) this.autoScrollButtom();

            this.pageIndex++;
          }
          if (cb) {
            const { scrollHeight } = this.$el.querySelector(".msg-box");
            cb(scrollHeight);
          }
        }).catch(err => {
          this.isLoadHistory = false
          console.error(err);
        });
      },
      // 发送消息
      send() {
        if (!this.msg || this.msg.match(/^\s+$/)) {
          return this.$message.error("不能发送空白内容");
        }
        this.isSend = true;
        try {
          this.socket.send(
            JSON.stringify({
              message: this.msg,
              token: this.token,
            })
          );
        } catch (error) {
          this.isSend = false;
          this.$message.error("发送失败");
          console.error(error);
        }
      },
      // 滚动到底部
      autoScrollButtom() {
        this.$nextTick(() => {
          const chatList = this.$el.querySelector(".msg-box");
          const { scrollHeight } = chatList;
          chatList.scrollTop = scrollHeight;
          chatList.removeEventListener('scroll', this.onLoadHistory)
          chatList.addEventListener('scroll', this.onLoadHistory);
        })
      },
      // 加载历史
      onLoadHistory() {
        const { scrollTop } = this.$el.querySelector(".msg-box");
        if (!this.isLoadHistory && scrollTop <= 10 && !this.finished) {
          this.isLoadHistory = true
          this.getMessageList(scrollHeight => {
            this.$nextTick(() => {
              const msgListDom = this.$el.querySelector(".msg-box");
              const { scrollHeight: msgListScrollHeight } = msgListDom;
              msgListDom.scrollTop = msgListScrollHeight - scrollHeight;
              this.isLoadHistory = false;
            })
          });
        }
      },
      // 获取用户列表
      chatroomtokenlist() {
        axios.get('/chatroom/chatroomtokenlist', {
          params: {
            page: 1,
            limit: 10
          }
        }).then(res => {
          if (res.data.code == 1) {
            this.contactList = res.data.data.data.map(item => {
              item.avatar = item.avatar.startsWith('https://') ? item.avatar : `/${item.avatar}`
              return item
            })
            if (!this.userActive) {
              this.contactList[0].msg_num = 0
              this.userActive = this.contactList[0]
            }
            this.createWebSocket();
            this.getMessageList()
          }
        })
      },
      // 用户选择
      onCantact(id) {
        if (this.userActive.user_id == id) return true
        this.userActive = this.contactList.find((item) => {
          if (item.user_id === id) {
            item.msg_num = 0
            return true
          }
        });
        this.pageIndex = 1
        this.msgList = []
        this.finished = false
        this.socket && this.socket.close()
        const chatList = this.$el.querySelector(".msg-box");
        chatList.removeEventListener('scroll', this.onLoadHistory)
        this.createWebSocket()
        // this.getChatToken()
        this.getMessageList();
      },
      // 用户搜索
      onSearch() {

      },

    }
  })
</script>

</html>